use crate::rtsp::marshal_trait::{Marshal, Unmarshal};
use crate::rtsp::sdp::fmtp::Fmtp;
use crate::rtsp::sdp::rtpmap::RtpMap;
use std::collections::HashMap;

pub mod fmtp;
pub mod rtpmap;

// Bandwidth 结构体，存储 SDP（Session Desription Protocol）带宽消息
#[derive(Debug, Clone, Default)]
pub struct Bandwidth {
    // 带宽类型
    b_type: String,
    // 带宽值
    bandwidth: u16,
}

impl Unmarshal for Bandwidth {
    fn unmarshal(raw_data: &str) -> Option<Self> {
        // 创建一个默认的 Bandwidth 实例
        let mut sdp_bandwidth = Bandwidth::default();

        // 按冒号分割原始字符串，得到带宽类型和带宽值部分
        let parameters: Vec<&str> = raw_data.split(':').collect();
        // 处理带宽类型部分
        if let Some(t) = parameters.first() {
            // 将带宽类型部分转换为 String 类型并赋值给 sdp_bandwidth 的 b_type 字段
            sdp_bandwidth.b_type = t.to_string();
        }

        // 处理带宽值部分
        if let Some(bandwidth) = parameters.get(1) {
            // 尝试将带宽值部分解析为 u16 类型
            if let Ok(bandwidth) = bandwidth.parse::<u16>() {
                // 解析成功则赋值给 sdp_bandwidth 的 bandwidth 字段
                sdp_bandwidth.bandwidth = bandwidth;
            }
        }

        // 返回解析后的 Bandwidth 实例
        Some(sdp_bandwidth)
    }
}

impl Marshal for Bandwidth {
    fn marshal(&self) -> String {
        // 格式化字符串，包含带宽类型和带宽值，并添加换行符
        format!("{}:{}\r\n", self.b_type, self.bandwidth)
    }
}

/*
以下是一个 SDP 示例，展示了 SDP 中各个字段的含义和格式：
v=0
o=- 946685052188730 1 IN IP4 0.0.0.0
s=RTSP/RTP Server
i=playback/robot=040082d087c335e3bd2b/camera=head/timerang1=1533620879-1533620898
t=0 0
a=tool:vlc 0.9.8a
a=type:broadcast
a=control:*
a=range:npt=0-
m=video 20003 RTP/AVP 97
b=RR:0
a=rtpmap:97 H264/90000
a=fmtp:97 profile-level-id=42C01E;packetization-mode=1;sprop-parameter-sets=Z0LAHtkDxWhAAAADAEAAAAwDxYuSAAAAAQ==,aMuMsgAAAAE=
a=control:track1
m=audio 11704 RTP/AVP 96 97 98 0 8 18 101 99 100
*/
// 存储 SDP 中每个流媒体的详细信息
#[derive(Debug, Clone, Default)]
pub struct SdpMediaInfo {
    // 媒体类型
    pub media_type: String,
    // 媒体流使用的端口号
    port: usize,
    // 媒体流使用的传输协议
    protocol: String,
    // 媒体流支持的负载类型列表
    fmts: Vec<u8>,
    // 可选的带宽信息
    bandwidth: Option<Bandwidth>,
    // RTP 映射信息，包含负载类型与编码格式、时钟速率等的对应关系
    pub rtpmap: RtpMap,
    // 可选的格式参数信息，根据不同的编码格式有不同的内容
    pub fmtp: Option<Fmtp>,
    /// 存储其他属性的键值对，如 "control" 等
    pub attributes: HashMap<String, String>,
}

impl Unmarshal for SdpMediaInfo {
    fn unmarshal(raw_data: &str) -> Option<Self> {
        // 创建一个默认的 SdpMediaInfo 实例
        let mut sdp_media = SdpMediaInfo::default();
        // 按空格分割原始字符串，得到各个参数部分
        let parameters: Vec<&str> = raw_data.split(' ').collect();

        // 处理媒体类型部分
        if let Some(para_0) = parameters.first() {
            // 将媒体类型部分转换为 String 类型并赋值给 sdp_media 的 media_type 字段
            sdp_media.media_type = para_0.to_string();
        }

        // 处理端口号部分
        if let Some(para_1) = parameters.get(1) {
            // 尝试将端口号部分解析为 usize 类型
            if let Ok(port) = para_1.parse::<usize>() {
                // 解析成功则赋值给 sdp_media 的 port 字段
                sdp_media.port = port;
            }
        }

        // 处理传输协议部分
        if let Some(para_2) = parameters.get(2) {
            // 将传输协议部分转换为 String 类型并赋值给 sdp_media 的 protocol 字段
            sdp_media.protocol = para_2.to_string();
        }

        // 初始化当前参数索引，从第 4 个参数开始处理负载类型
        let mut cur_param_idx = 3;

        // 循环处理剩余的参数，将其解析为负载类型并添加到 fmts 向量中
        while let Some(fmt_str) = parameters.get(cur_param_idx) {
            if let Ok(fmt) = fmt_str.parse::<u8>() {
                sdp_media.fmts.push(fmt);
            }
            cur_param_idx += 1;
        }

        // 返回解析后的 SdpMediaInfo 实例
        Some(sdp_media)
    }
}

impl Marshal for SdpMediaInfo {
    fn marshal(&self) -> String {
        // 将 fmts 向量中的负载类型转换为字符串并使用空格连接
        let fmts_str = self
            .fmts
            .iter()
            .map(|b| b.to_string())
            .collect::<Vec<String>>()
            .join(" ");

        // 处理带宽信息，如果存在则格式化为字符串，否则为空字符串
        let bandwidth = if let Some(bandwidth) = &self.bandwidth {
            format!("b={}", bandwidth.marshal())
        } else {
            String::from("")
        };

        // 格式化基本的媒体流信息
        let mut sdp_media_info = format!(
            "m={} {} {} {}\r\n{}a=rtpmap:{}",
            self.media_type,
            self.port,
            self.protocol,
            fmts_str,
            bandwidth,
            self.rtpmap.marshal()
        );

        // 处理格式参数信息，如果存在则添加到格式化字符串中
        if let Some(fmtp) = &self.fmtp {
            sdp_media_info = format!("{}a=fmtp:{}", sdp_media_info, fmtp.marshal());
        }

        // 处理其他属性信息，将其添加到格式化字符串中
        for (k, v) in &self.attributes {
            sdp_media_info = format!("{sdp_media_info}a={k}:{v}\r\n");
        }

        // 返回格式化后的字符串
        sdp_media_info
    }
}

// Sdp 结构体，存储整个 SDP 会话信息
#[derive(Debug, Clone, Default)]
pub struct Sdp {
    // 原始 SDP 字符串
    pub raw_string: String,
    // SDP 版本号
    version: u16,
    // 会话的发起者和会话标识符信息
    origin: String,
    // 会话的名称或标题
    session: String,
    // 会话的连接信息，如地址类型和地址
    connection: String,
    // 会话的时间信息，包括开始时间和结束时间
    timing: String,
    // 存储多个媒体流信息的向量
    pub medias: Vec<SdpMediaInfo>,
    // 存储会话级属性的键值对
    attributes: HashMap<String, String>,
}

impl Unmarshal for Sdp {
    fn unmarshal(raw_data: &str) -> Option<Self> {
        let mut sdp = Sdp {
            raw_string: raw_data.to_string(),
            ..Default::default()
        };

        // 按换行符分割原始字符串，得到每一行信息
        let lines: Vec<&str> = raw_data.split(|c| c == '\r' || c == '\n').collect();
        // 遍历每一行信息
        for line in lines {
            // 如果行为空则跳过
            if line.is_empty() {
                continue;
            }
            // 按等号分割每一行，得到键值对部分
            let kv: Vec<&str> = line.trim().splitn(2, '=').collect();
            // 如果键值对部分少于 2 个，则记录错误信息并跳过
            if kv.len() < 2 {
                log::error!("Sdp current line : {} parse error!", line);
                continue;
            }

            // 根据键的不同进行不同的处理
            match kv[0] {
                // 处理 SDP 版本号
                "v" => {
                    if let Ok(version) = kv[1].parse::<u16>() {
                        sdp.version = version;
                    }
                }
                // 处理会话发起者和会话标识符信息
                "o" => {
                    sdp.origin = kv[1].to_string();
                }
                // 处理会话名称或标题
                "s" => {
                    sdp.session = kv[1].to_string();
                }
                // 处理会话连接信息
                "c" => {
                    sdp.connection = kv[1].to_string();
                }
                // 处理会话时间信息
                "t" => {
                    sdp.timing = kv[1].to_string();
                }
                // 处理媒体流信息
                "m" => {
                    if let Some(sdp_media) = SdpMediaInfo::unmarshal(kv[1]) {
                        sdp.medias.push(sdp_media);
                    }
                }
                // 处理带宽信息
                "b" => {
                    if let Some(cur_media) = sdp.medias.last_mut() {
                        cur_media.bandwidth = Some(Bandwidth::unmarshal(kv[1]).unwrap());
                    } else {
                        continue;
                    }
                }
                // 处理属性信息
                "a" => {
                    // 按冒号分割属性信息，得到属性名和属性值部分
                    let attribute: Vec<&str> = kv[1].splitn(2, ':').collect();

                    let attr_name = attribute[0];
                    let attr_value = if let Some(val) = attribute.get(1) {
                        val
                    } else {
                        ""
                    };

                    if let Some(cur_media) = sdp.medias.last_mut() {
                        if attribute.len() == 2 {
                            match attr_name {
                                // 处理 RTP 映射信息
                                "rtpmap" => {
                                    if let Some(rtpmap) = RtpMap::unmarshal(attr_value) {
                                        cur_media.rtpmap = rtpmap;
                                        continue;
                                    }
                                }
                                // 处理格式参数信息
                                "fmtp" => {
                                    cur_media.fmtp =
                                        Fmtp::new(&cur_media.rtpmap.encoding_name, attr_value);
                                    continue;
                                }
                                _ => {}
                            }
                        }
                        // 将其他属性添加到媒体流的属性集合中
                        cur_media
                            .attributes
                            .insert(attr_name.to_string(), attr_value.to_string());
                    } else {
                        // 如果没有当前媒体流，则将会话级属性添加到 Sdp 的属性集合中
                        sdp.attributes
                            .insert(attr_name.to_string(), attr_value.to_string());
                    }
                }
                _ => {
                    // 记录未解析的行信息
                    log::info!("not parsed: {}", line);
                }
            }
        }

        // 返回解析后的 Sdp 实例
        Some(sdp)
    }
}

impl Marshal for Sdp {
    fn marshal(&self) -> String {
        // 格式化 SDP 会话的基本信息
        let mut sdp_str = format!(
            "v={}\r\no={}\r\ns={}\r\nc={}\r\nt={}\r\n",
            self.version, self.origin, self.session, self.connection, self.timing
        );

        // 处理会话级属性信息，将其添加到格式化字符串中
        for (k, v) in &self.attributes {
            sdp_str = format!("{sdp_str}a={k}:{v}\r\n");
        }

        // 处理每个媒体流信息，将其添加到格式化字符串中
        for media_info in &self.medias {
            sdp_str = format!("{}{}", sdp_str, media_info.marshal());
        }

        // 返回格式化后的字符串
        sdp_str
    }
}
